#include <stdint.h>
#include "../libc/mem.h"
#include "../cpu/port.h"
#include "screen.h"

// 私有方法定义
int get_current_offset();
void set_current_offset(int offset);
int get_row_num(int offset);
int get_col_num(int offset);
int get_offset(int rowNum, int colNum);

void kprint(char *str) {
    // 获取当前光标位置
    int offset = get_current_offset();
    uint8_t *videoMemory = (uint8_t *) VIDEO_MEMORY_ADDRESS;
    
    // 打印字符串
    int i = 0;
    while(str[i]) {
        int rownNum = get_row_num(offset);
        if(rownNum >= MAX_ROW_NUM) {
            memcopy(videoMemory + MAX_COL_NUM * 2, videoMemory, MAX_COL_NUM * (MAX_ROW_NUM - 1) * 2);
            int lastRowOffset = get_offset(MAX_ROW_NUM - 1, 0);
            offset = lastRowOffset;
            int i;
            for (i = 0; i < MAX_COL_NUM; i++) {
                videoMemory[lastRowOffset++] = ' ';
                videoMemory[lastRowOffset++] = WHITE_ON_BLACK;
            }
        }
        if(str[i] == '\n') {
            offset = get_offset(rownNum + 1, 0);
        } else {
            videoMemory[offset++] = str[i];
            videoMemory[offset++] = WHITE_ON_BLACK;
        }
        set_current_offset(offset);
        i++;
    }
}

int get_current_offset() {
    port_byte_out(REG_SCREEN_CTRL, 14);
    int offset = port_byte_in(REG_SCREEN_DATA) << 8;
    port_byte_out(REG_SCREEN_CTRL, 15);
    offset += port_byte_in(REG_SCREEN_DATA);
    return offset * 2;
}

void set_current_offset(int offset) {
    offset /= 2;
    port_byte_out(REG_SCREEN_CTRL, 14);
    port_byte_out(REG_SCREEN_DATA, (uint8_t) (offset >> 8));
    port_byte_out(REG_SCREEN_CTRL, 15);
    port_byte_out(REG_SCREEN_DATA, (uint8_t) (offset & 0xff));
}

int get_row_num(int offset) {
    offset /= 2;
    return offset / MAX_COL_NUM;
}

int get_col_num(int offset) {
    offset /= 2;
    return offset % MAX_COL_NUM;
}

int get_offset(int rowNum, int colNum) {
    return (MAX_COL_NUM * rowNum + colNum) * 2;
}

void clear_screen() {
    uint8_t *videoMemory = (uint8_t *) VIDEO_MEMORY_ADDRESS;
    int screenSize = MAX_COL_NUM * MAX_ROW_NUM;
    int i;
    for (i = 0; i < screenSize; i++) {
        videoMemory[i * 2] = ' ';
        videoMemory[i * 2 + 1] = WHITE_ON_BLACK;
    }
    set_current_offset(0);
}

void kprint_backspace() {
    int offset = get_current_offset();
    int colNum = get_col_num(offset);
    uint8_t *videoMemory = (uint8_t *) VIDEO_MEMORY_ADDRESS;
    if(colNum > 0) {
        videoMemory[offset - 2] = ' ';
        videoMemory[offset - 1] = WHITE_ON_BLACK;
        set_current_offset(offset - 2);
    }
}
